#include "IndexBuffer.h"
#include "Model.h"
#include "Renderer.h"
#include "ShaderProgram.h"
#include "Texture2D.h"
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "GlfwWindow.h"
#include "glm/ext/matrix_transform.hpp"
#include "glm/fwd.hpp"
#include "stb_image.h"

#include <iostream>
#include <string>
using namespace std;

int main(int argc, char *argv[])
{
    GlfwWindowManager window(1200, 900);
    if (!window.initWindow("LearnOpenGL")) {
        std::cout << "Failed to create GLFW window" << std::endl;
    }

    stbi_set_flip_vertically_on_load(true);
    ShaderProgram modelShader("./shaders/example_model/model_vertex.shader", "./shaders/example_model/model_fragment.shader");

    modelShader.bind();
    Model outModel("./textures/nanosuit/nanosuit.obj");
    modelShader.setUniform1f("u_material1.shininess", 32.0f);

    // 点光源颜色
    glm::vec3 lightColor(0.1f, 0.1f, 0.1f);

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.2f, 0.2f, 0.3f, 1.0f);
    window.loopRender([&]() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        auto cameraPos   = window.getCameraPos();
        auto cameraFront = window.getCameraFront();

        modelShader.bind();
        modelShader.setUniformVec3f("u_viewPos", cameraPos);

        // view/projection transformations
        modelShader.setUniformMat4fv("u_proj", window.getProj());
        modelShader.setUniformMat4fv("u_view", window.getView());

        // directional light
        modelShader.setUniform3f("u_dirLight.direction", -0.2f, -1.0f, -0.3f);
        modelShader.setUniform3f("u_dirLight.ambient", 1.0f * lightColor.r, 1.0f * lightColor.g, 1.0f * lightColor.b);
        modelShader.setUniform3f("u_dirLight.diffuse", 1.0f * lightColor.r, 1.0f * lightColor.g, 1.0f * lightColor.b);
        modelShader.setUniform3f("u_dirLight.specular", 1.0f * lightColor.r, 1.0f * lightColor.g, 1.0f * lightColor.b);

        {
            glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
            model           = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f));
            modelShader.setUniformMat4fv("u_model", model);
            outModel.draw(modelShader);
        }
    });
    return 0;
}